<template>
  <div
    class="overflow-hidden cursor-pointer"
    :style="size"
    @click="fileRef?.click()"
  >
    <input
      ref="fileRef"
      type="file"
      :accept="accept"
      style="display: none"
      @change="change"
    />
    <img
      v-if="src"
      class="w-full h-full object-center object-cover"
      :src="src"
    />
    <slot v-else>
      <svg
        fill="none"
        stroke="currentColor"
        viewBox="0 0 24 24"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          stroke-width="2"
          d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
        ></path>
      </svg>
    </slot>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, toRefs, computed, inject, watch } from "vue";
import { isString, isNull } from "../utils";
import { Form, formInjectKey } from "./types";

export default defineComponent({
  props: {
    width: {
      type: Number,
      required: true,
    },
    height: Number,
    accept: {
      type: String,
      default: "image/png, image/jpeg, image/gif, image/jpg",
    },
    modelValue: {
      type: [String, File],
      required: true,
    },
    maxSize: Number,
    name: {
      type: String,
      required: true,
    },
  },
  emits: ["update:modelValue"],
  setup(props, { emit }) {
    // 处理预览大小
    const { width, height, maxSize, name } = toRefs(props);
    const size = computed(() => {
      const w = width.value,
        h = height.value ? height.value : w;
      return {
        width: w + "px",
        height: h + "px",
      };
    });
    const form = inject<Form>(formInjectKey),
      fileRef = ref<HTMLInputElement>(),
      src = ref("");
    // 处理初值
    if (isString(props.modelValue)) src.value = props.modelValue;
    watch(
      () => props.modelValue,
      (val) => {
        if (isString(val)) src.value = val;
      },
      { immediate: true }
    );
    // 处理图片预览
    const change = () => {
      if (!fileRef.value || isNull(fileRef.value.files)) return;
      const file = fileRef.value.files[0];
      if (!file) return;
      // 验证图片文件大小
      if (maxSize.value && file.size / 1024 > maxSize.value) {
        return form?.setErrors({
          [name.value]: [`图片文件大小超过${maxSize.value}KB`],
        });
      }
      // 读取图片内容
      const reader = new FileReader();
      reader.readAsDataURL(file);
      reader.onload = () => {
        src.value = reader.result as string;
      };
      // 更新绑定的值
      emit("update:modelValue", file);
    };
    return {
      fileRef,
      change,
      src,
      size,
    };
  },
});
</script>
